package com.seanbot.armstrong.passcodestoragerc4;

import java.io.UnsupportedEncodingException;
import java.math.BigInteger;
import java.nio.charset.CharsetEncoder;

public class CipherAlgorithm {
	String key;
	int k = 0;
	int l = 0;
	byte[] streamArray;
	byte[] ptByteArray;

	public CipherAlgorithm(String key) throws UnsupportedEncodingException {
		this.key = key;
	}

	public void createStream() throws UnsupportedEncodingException {
		k = 0;
		l = 0;

		this.streamArray = new byte[256];
		for (int i = 0; i < 256; i++)
			streamArray[i] = (byte) i;
		byte[] keyArray = key.getBytes("UTF8");
		for (int i = 0, j = 0; i < 256; i++) {
			j = (j + streamArray[i] + keyArray[i % key.length()]) & 0xff;
			byte temp = streamArray[i];
			streamArray[i] = streamArray[j];
			streamArray[j] = temp;
		}
	}

	public byte getStreamNext() throws UnsupportedEncodingException {

		byte byt;

		k = (k + 1) & 0xff;
		l = (l + streamArray[k]) & 0xff;

		// swap streamArray[k] with [l]
		byte temp = streamArray[k];
		streamArray[k] = streamArray[l];
		streamArray[l] = temp;

		// set byt to the stream @ pos i and return it
		byt = streamArray[(streamArray[k] + streamArray[l]) & 0xff];
		return byt;
	}

	public String encrypt(String plainText) throws UnsupportedEncodingException {
		String encryptedText;
		byte[] a = textToByteArray(plainText);
		for (int i = 0; i < plainText.length(); i++) {
			a[i] = (byte) (a[i] ^ getStreamNext());
		}
		encryptedText = byteArrayToHexString(a);
		return encryptedText;
	}

	public String decrypt(String cipherText)
			throws UnsupportedEncodingException {
		String decryptedText;
		byte[] a = hexToByteArray(cipherText);
		for (int i = 0; i < a.length; i++) {
			a[i] = (byte) (a[i] ^ getStreamNext());
		}
		decryptedText = hexToString(byteArrayToHexString(a));
		return decryptedText;
	}

	private String hexToString(String hexStr) {
		StringBuilder plainText = new StringBuilder();
		for(int i = 0; i < hexStr.length(); i+=2){
			String str = hexStr.substring(i, i+2);
			plainText.append((char)Integer.parseInt(str, 16));
		}
		return plainText.toString();
	}

	public byte[] hexToByteArray(String st) {
		int length = st.length();
		byte[] a = new byte[length / 2];
		for (int i = 0; i < length; i += 2) {
			a[i / 2] = (byte) ((Character.digit(st.charAt(i), 16) << 4) + Character
					.digit(st.charAt(i + 1), 16));
		}
		return a;
	}

	public String byteArrayToHexString(byte[] a) {
		BigInteger bi = new BigInteger(1, a);
		return String.format("%0" + (a.length << 1) + "X", bi);
	}

	public byte[] textToByteArray(String st) {
		byte[] a = null;
		a = st.getBytes();
		return a;
	}

}
